﻿namespace DimensionsHelper.CommandLine.ConsoleTracer;

public class ConsoleRange : INavigatorRange
{
    private readonly INavigatorLine _line;
    private ConsoleColor? _backgroundColor;
    private string _content;
    private int _endCharacter;
    private int _endLine;
    private ConsoleColor? _foregroundColor;

    // 单链表就够用了，一般不需要从后向前查找。
    private INavigatorRange? _next;
    private int _startCharacter;
    private int _startLine;

    public ConsoleRange(INavigatorLine line, ConsolePosition start, ConsoleRange? previous)
    {
        _line = line;
        _startLine = start.Line;
        _startCharacter = start.Character;
        _endLine = _startLine;
        _endCharacter = _startCharacter;
        
        if (previous != null)
        {
            _next = previous._next;
            previous._next = this;
        }

        _content = string.Empty;
    }


    public event EventHandler<NavigatorLocationChangedArgs>? LocationChanged;

    public INavigatorLine GetLine()
    {
        return _line;
    }

    public INavigatorRange? Next()
    {
        return _next;
    }


    public ConsoleLocation GetLocation()
    {
        return ConsoleLocation.Create(
            ConsolePosition.Create(_startLine, _startCharacter),
            ConsolePosition.Create(_endLine, _endCharacter));
    }


    public void Shift(ConsolePosition start)
    {
        ConsoleLocation loc = GetLocation();
        if (start == loc.Start)
        {
            return;
        }

        Clear();
        _startLine = start.Line;
        _startCharacter = start.Character;
        ConsolePosition end = RefreshInternal(start);
        _endLine = end.Line;
        _endCharacter = end.Character;
        Next()?.Shift(end);
    }


    public void Shift(int shiftLine)
    {
        if (shiftLine == 0)
        {
            return;
        }

        Shift(ConsolePosition.Create(_startLine + shiftLine, _startCharacter));
    }


    public void Refresh()
    {
        ConsolePosition end = RefreshInternal(GetLocation().Start);
        // 更新后续区域位置
        if (end.Line != _endLine || end.Character != _endCharacter)
        {
            Next()?.Shift(end);
            _endLine = end.Line;
            _endCharacter = end.Character;
        }
    }


    public INavigatorRange SetForeground(ConsoleColor color)
    {
        _foregroundColor = color;
        RefreshInternal(GetLocation().Start);
        return this;
    }


    public INavigatorRange SetBackground(ConsoleColor color)
    {
        _backgroundColor = color;
        RefreshInternal(GetLocation().Start);
        return this;
    }


    public INavigatorRange UpdateContent(string newContent)
    {
        ConsoleLocation loc = GetLocation();
        _content = newContent;
        Refresh();
        ConsoleLocation newLoc = GetLocation();
        if (loc != newLoc)
        {
            LocationChanged?.Invoke(this, new NavigatorLocationChangedArgs(newLoc));
        }

        return this;
    }


    public void Clear()
    {
        ConsoleHelper.ClearText(GetLocation());
    }


    internal ConsolePosition RefreshInternal(ConsolePosition start)
    {
        ConsoleHelper.SetCursorPosition(start);
        return ConsoleHelper.Write(_content, _foregroundColor, _backgroundColor);
    }
}